package myJs.user.data

import myJs.Utils._
import scala.scalajs.js.Dynamic.{global => g}
import org.scalajs.dom.ext.Ajax
import myJs.Implicits.{JArJDS, _}
import myJs.myPkg.{BootstrapValidator, LayerOptions, MultiSelectOptions, Swal, SwalOptions}

import scalatags.Text.all.{h5, _}
import myJs.myPkg.jquery._
import myJs.myPkg.bootstrap.Bootstrap.default._
import myJs.tool.Tool
import myJs.tool.Tool._
import org.scalajs.dom.{Element, document}

import scala.scalajs.js
import scala.scalajs.js.JSON
import org.scalajs.macrotaskexecutor.MacrotaskExecutor.Implicits._

/** Created by yz on 16/10/2020
  */
object NewGroupModal {

  val tabId = "metData"
  val groupModalId = "groupModal"
  val groupFormId = "groupForm"

  def init = {
    bootStrapValidator
    refreshGroup
    registerEvent
  }

  def registerEvent = {
    $(s"#${tabId} #${groupModalId}").on(
      "shown.bs.modal",
      () => {
        val bv = $(s"#${tabId} #${groupFormId}").bv
        if (!bv.isValidField("fileName")) {
          bv.revalidateField("fileName")
        }
      }
    )
    $(s"#${tabId} #${groupModalId}").on(
      "hide.bs.modal",
      () => {
        val bv = $(s"#${tabId} #${groupFormId}").bv
        bv.resetForm(true)
      }
    )
    $(document.body).on(
      "click",
      s"#${tabId} .myMoveUp",
      "",
      (y: Element) => {
        moveUp(y)
      }
    )
    $(document.body).on(
      "click",
      s"#${tabId} .myMoveDown",
      "",
      (y: Element) => {
        moveDown(y)
      }
    )
    $(document.body).on(
      "click",
      s"#${tabId} .myNewGroup",
      "",
      (y: Element) => {
        newGroup
      }
    )
    $(document.body).on(
      "click",
      s"#${tabId} .myAddGroup",
      "",
      (y: Element) => {
        addGroup
      }
    )
    $(document.body).on(
      "click",
      s"#${tabId} #${groupModalId} .myMoveRight",
      "",
      (y: Element) => {
        moveToRight(y)
      }
    )
    $(document.body).on(
      "click",
      s"#${tabId} .myMoveLeft",
      "",
      (y: Element) => {
        moveToLeft(y)
      }
    )
    $(document.body).on(
      "click",
      s"#${tabId} .myMoveLeftAll",
      "",
      (y: Element) => {
        moveLeftAll(y)
      }
    )
    $(document.body).on(
      "click",
      s"#${tabId} .deleteButton",
      "",
      (y: Element) => {
        deleteGroup(y)
      }
    )
  }

  def myGroupChange = {
    setDisable
    changeSize
    clearHr
  }

  def clearHr = {
    $(s".myEachGroup:first-child").find("hr").remove()
  }

  def setDisable = {
    val size = $(s"#${groupModalId} .myEachGroup").mapElems(y => y).size
    size match {
      case x if x <= 2 =>
        $(".deleteButton").setDisabled(true)
      case x if x > 2 =>
        $(".deleteButton").setDisabled(false)
    }
  }

  def moveLeftAll(y: Element) = {
    val right = getRight(y)
    val rightOptions = right.children(":visible")
    r2l(rightOptions, left)
    refreshSampleNum(y)
  }

  def getNewFileName(id: String) = {
    val url = g.jsRoutes.controllers.GroupFileDataController.getNewFileName().url.toString
    Ajax.get(url = s"${url.noCache}&id=${id}", headers = Map("Content-Type" -> "application/json")).map { xhr =>
      val rs = xhr.responseText.toJDJAn.toMyJDS
      rs("fileName").fileNamePrefix
    }
  }

  def left = {
    $("#multi_d")
  }

  def multiSelectInit = {
    val options = MultiSelectOptions.keepRenderingSort(false)
    left.multiselect(options)
  }

  def groupShow(id: String) = {
    val url = g.jsRoutes.controllers.MatrixFileDataController.getHeaders().url.toString
    Ajax.get(url = s"${url.noCache}&id=${id}", headers = Map("Content-Type" -> "application/json")).flatMap { xhr =>
      getNewFileName(id).map { newFileName =>
        val rs = xhr.responseText.toJDJAn
        val headers = rs("headers").toJArS
        val html = headers.zipWithIndex
          .map { case (v, i) =>
            option(value := s"${v}", dataId := s"${i}", v)
          }
          .mkString("&nbsp;")
        left.html(html)
        multiSelectInit
        $(s"#${groupModalId} #fileName").text(rs("fileName").toString)
        $(s"#${groupModalId}").findInputByName("fileName").`val`(newFileName)
        $(s"#${groupModalId} #totalSampleNum").text(s"${headers.size}")
        $(s"#${groupModalId} #remainSampleNum").text(s"${headers.size}")
        refreshGroup
        $(s"#${groupModalId}").modal("show")
      }
    }
  }

  def moveToLeft(y: Element) = {
    val right = getRight(y)
    val rightOptions = right.find("> option:selected")
    r2l(rightOptions, left)
    refreshSampleNum(y)
  }

  def getRight(y: Element) = {
    $(y).parents(".myEachGroup").findInputByName("sampleNames[]")
  }

  def r2l(rightOptions: JQuery, left: JQuery) = {
    val leftOptions = left.children()
    val leftElems = leftOptions.mapElems(y => y)
    rightOptions.mapElems(y => y).foreach { y =>
      val rightId = $(y).dataId.toInt
      val elemOp = leftElems.find { z =>
        val leftId = $(z).dataId.toInt
        leftId > rightId
      }
      elemOp
        .map { elem =>
          $(y).insertBefore($(elem))
        }
        .getOrElse {
          left.append($(y))
        }
    }
    sampleNamesValid
  }

  def sampleNamesValid = {
    val vys = Tool.getInputByName("sampleNames[]").mapElems(y => y).map { y =>
      $(y).myVisVal -> y
    }
    val bv = $(s"#${groupFormId}").bv
    vys.foreach { case (v, y) =>
      if (v.nonBlank) {
        bv.updateStatus($(y), "VALID", "blank")
      } else {
        bv.updateMessage($(y), "blank", s"${messages("null")}")
        bv.updateStatus($(y), "INVALID", "blank")
      }
    }
  }

  def moveToRight(y: Element) = {
    val leftOptions = left.find("> option:selected")
    val right = getRight(y)
    right.append(leftOptions)
    sampleNamesValid
    refreshSampleNum(y)
  }

  def refreshSampleNum(y: Element) = {
    refreshLeftSampleNum
    refreshRightSampleNum(y)
  }

  def refreshRightSampleNum(y: Element) = {
    val right = getRight(y)
    val jq = $(y).parents(".myEachGroup").find("#sampleNum")
    val sampleNum = right.find(">option").mapElems(y => y).size
    jq.text(s"${sampleNum}")
  }

  def refreshLeftSampleNum = {
    val sampleNum = left.find(">option").mapElems(y => y).size
    $(s"#${groupModalId} #remainSampleNum").text(s"${sampleNum}")
  }

  def deleteGroup(y: Element) = {
    moveLeftAll(y)
    $(y).parents(".myEachGroup").remove()
    $(s"#${groupFormId}").bv.revalidateField("sampleNames[]").revalidateField("groupNames[]")
    myGroupChange
    refreshLeftSampleNum
  }

  def newGroup = {
    val bv = $(s"#${tabId} #${groupFormId}").bv
    bv.validate()
    val valid = bv.isValid()
    if (valid && sampleNamesCheck && sampleNamesSelectCheck) {
      val element = div(
        id := "content",
        span(id := "info", messages("running"), span(id := "progress", "。。。")),
        " ",
        img(src := "/assets/images/running2.gif", cls := "runningImage", width := 30, height := 20)
      ).render
      val layerOptions = LayerOptions.title(Tool.zhInfo).closeBtn(0).skin("layui-layer-molv").btn(js.Array())
      val index = layer.alert(element, layerOptions)
      val url = g.jsRoutes.controllers.DataController.newGroup().url.toString
      val dict = js.Dictionary(
        "fileName" -> $(s"#${groupModalId}").findInputByName("fileName").myVal,
        "groupNames" -> $(s"#${groupModalId}").findInputByName("groupNames[]").myVals,
        "sampleNames" -> $(s"#${groupModalId}").findInputByName("sampleNames[]").myVisVals,
        "isPaired" -> $(s"#${groupModalId}").findInputByName("isPaired").prop("checked")
      )
      val data = JSON.stringify(dict)
      Ajax.post(url = s"${url}", data = data, headers = Map("Content-Type" -> "application/json")).map { xhr =>
        val rs = xhr.responseText.toJDJAn
        layer.close(index)
        $(s"#${tabId} #${groupModalId}").modal("hide")
        MetDataTab.refreshTable { () =>
          val options = SwalOptions(
            `type` = "success",
            title = messages("success"),
            text = messages("AddSuccessfully")
          )
          Swal.swal(options)
        }
      }
    }
  }

  def addGroup = {
    val isEmpty = $("#groups").html().trim.isEmpty
    val myHr = if (isEmpty) {
      span()
    } else hr
    val html = div(
      `class` := "row myEachGroup",
      marginBottom := 20,
      myHr,
      div(
        `class` := "col-sm-5",
        div(
          `class` := "form-group",
          label(`class` := "control-label col-sm-4", s"${messages("groupName")}:"),
          div(`class` := "col-sm-6", input(`type` := "text", `class` := "form-control", name := "groupNames[]")),
          div(`class` := "col-sm-2 control-label", paddingLeft := 0, span("(", span(id := "sampleNum", "0"), ")"))
        ),
        button(
          `type` := "button",
          `class` := "btn btn-default btn-block myMoveRight",
          i(`class` := "fa fa-chevron-right")
        ),
        button(
          `type` := "button",
          `class` := "btn btn-default btn-block myMoveLeft",
          i(`class` := "fa fa-chevron-left")
        ),
        button(`type` := "button", `class` := "btn btn-default btn-block myMoveLeftAll", i(`class` := "fa fa-backward"))
      ),
      div(
        `class` := "col-sm-5",
        paddingRight := 0,
        div(
          `class` := "form-group",
          div(`class` := "col-sm-12", select(`class` := "form-control", name := "sampleNames[]", size := 9, multiple))
        )
      ),
      div(
        `class` := "col-sm-2",
        button(
          `type` := "button",
          `class` := "btn btn-default btn-block myMoveUp",
          title := messages("moveUp"),
          i(`class` := "fa fa-arrow-up")
        ),
        button(
          marginTop := 10,
          `type` := "button",
          `class` := "btn btn-default btn-block myMoveDown",
          title := messages("moveDown"),
          i(`class` := "fa fa-arrow-down")
        ),
        button(
          marginTop := 60,
          `type` := "button",
          title := messages("delete"),
          `class` := "btn btn-default btn-block deleteButton",
          i(`class` := "fa fa-trash")
        )
      )
    )
    $("#groups").append(html.render)
    myGroupChange
    val bv = $(s"#${groupFormId}").bv
    bv.addField($(s".myEachGroup:last-child").findInputByName("sampleNames[]"))
      .addField($(s".myEachGroup:last-child").findInputByName("groupNames[]"))
  }

  def refreshGroup = {
    $("#groups").empty()
    (1 to 3).foreach { i =>
      addGroup
    }
  }

  def changeSize = {
    val size = $(s"#${groupModalId} .myEachGroup").mapElems(y => y).size
    val finalSize = math.min(3, size) * 13
    left.attr("size", finalSize)
  }

  def moveUp(y: Element) = {
    val jq = getRight(y).find(":selected:not(span):not(.hidden)")
    jq.first().prev().before(jq)
  }

  def moveDown(y: Element) = {
    val jq = getRight(y).find(":selected:not(span):not(.hidden)")
    jq.last().next().after(jq)
  }

  def sampleNamesCheck = {
    sampleNamesValid
    val vys = Tool.getInputByName("sampleNames[]").mapElems(y => y).map { y =>
      $(y).myVisVal -> y
    }
    vys.forall(_._1.nonBlank)
  }

  def sampleNamesSelectCheck = {
    val b = left.find(">option").mapElems(y => y).isEmpty
    if (!b) {
      layer.msg(s"${messages("allSamplesShouldBeAllocated")}", LayerOptions.icon(5).time(3000))
    }
    b
  }

  def bootStrapValidator = {
    def differentF: js.Function = (value: String, bv: BootstrapValidator, jq: JQuery) => {
      val vElemsMap = Tool
        .getInputByName("groupNames[]")
        .mapElems(y => y)
        .map { y =>
          val v = $(y).myVal
          v -> y
        }
        .filter { case (v, y) =>
          v.nonBlank
        }
        .groupMap(_._1)(_._2)
      vElemsMap.foreach { case (v, ys) =>
        if (ys.size > 1) {
          ys.foreach { y =>
            bv.updateStatus($(y), "INVALID", "blank")
          }
        } else {
          ys.foreach { y =>
            bv.updateStatus($(y), "VALID", "blank")
          }
        }
      }
      true
    }

    val maxNumber = Double.MaxValue
    val url = g.jsRoutes.controllers.GroupFileDataController.fileNameNonExistCheck().url.toString
    val dict: js.Dictionary[js.Any] = js.Dictionary(
      "feedbackIcons" -> js.Dictionary(
        "valid" -> "",
        "invalid" -> "glyphicon glyphicon-remove",
        "validating" -> "glyphicon glyphicon-refresh"
      ),
      "fields" -> js.Dictionary(
        "groupNames[]" -> {
          val info = messages("groupName")
          js.Dictionary(
            "validators" -> js.Dictionary(
              "notEmpty" -> js.Dictionary(
                "message" -> s"${messages("null")}"
              ),
              "callback" -> js.Dictionary(
                "callback" -> differentF
              ),
              "blank" -> js.Dictionary(
                "message" -> s"${messages("notSame", info)}！"
              )
            )
          )
        },
        "sampleNames[]" -> js.Dictionary(
          "validators" -> js.Dictionary(
            "blank" -> js.Dictionary(
            )
          )
        ),
        "fileName" -> {
          val info = messages("fileName")
          js.Dictionary(
            "validators" -> js.Dictionary(
              "notEmpty" -> js.Dictionary(
                "message" -> s"${messages("null")}"
              ),
              "remote" -> js.Dictionary(
                "message" -> s"${messages("exist")}",
                "url" -> url,
                "type" -> "POST",
                "delay" -> 1000
              )
            )
          )
        }
      )
    )
    $(s"#${tabId} #${groupFormId}").bootstrapValidator(dict)
  }

}
